package spring.cloud.service.task.service.impl;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.curator.framework.CuratorFramework;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import spring.cloud.service.task.domain.zooKeeperAndNamespace.ZooKeeper;
import spring.cloud.service.task.dto.NamespaceDto;
import spring.cloud.service.task.dto.ZooKeeperDto;
import spring.cloud.service.task.mapper.NameSpaceDtoMapper;
import spring.cloud.service.task.mapper.TaskDtoMapper;
import spring.cloud.service.task.mapper.ZooKeeperDtoMapper;
import spring.cloud.service.task.service.ZooKeeperService;
import spring.cloud.service.task.utils.PageInfo;
import spring.cloud.service.task.utils.Result;
import spring.cloud.tasks.common.CuratorUtils;
import spring.cloud.tasks.common.curator.Curator;
import spring.cloud.tasks.common.curator.CuratorFactory;
import spring.cloud.tasks.common.curator.CuratorInfo;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Setter
@Getter
@Slf4j
public class ZooKeeperServiceImpl implements ZooKeeperService {
    @Resource
    private ZooKeeperDtoMapper zooKeeperDtoMapper;
    @Autowired
    private NameSpaceDtoMapper nameSpaceDtoMapper;
    @Autowired
    private TaskDtoMapper taskConfigurationDtoMapper;

    public static Curator getCurator(ZooKeeperService zooKeeperService, String nameSpace) {
        CuratorInfo curatorInfo = zooKeeperService.getCuratorInfo(nameSpace);
        Curator curator = CuratorFactory.getCurator(curatorInfo, CuratorFactory.shortTime_true);
        return curator;
    }

    /**
     * 必须单独启动一个会话进行删除
     *
     * @param curatorInfo
     */
    public static void deleteNameSpaceInZooKeeper(CuratorInfo curatorInfo) {
        CuratorFramework curatorFramework = null;
        try {
            curatorFramework = spring.cloud.tasks.common.curator.CuratorFactory.connect(curatorInfo.getAddressList(), curatorInfo.getDigest(), null, CuratorFactory.shortTime_true);
            curatorFramework.delete().deletingChildrenIfNeeded().forPath("/" + curatorInfo.getNamespaceKey());
            log.info("删除命名空间成功 {}", curatorInfo.getNamespaceKey());
        } catch (Exception e) {
            log.warn("删除命名空间失败:{}", curatorInfo.getNamespaceKey(), e);
            try {
                CuratorUtils.deleteRecursive(curatorFramework, "/" + curatorInfo.getNamespaceKey());
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        } finally {
            if (curatorFramework != null) {
                curatorFramework.close();
            }
        }
    }

    @Override
    public PageInfo getZooKeeperList(String description, String status, Integer page, Integer limit) {
        int count = zooKeeperDtoMapper.selectAllCount(description, status);
        if (count == 0) {
            PageInfo pageInfo = new PageInfo(new ArrayList<ZooKeeper>());
            return pageInfo;
        } else {
            PageInfo pageInfo = new PageInfo(page, limit, count);
            Integer pageOffset = pageInfo.getCurrentPageOffset();
            Integer pageSize = limit.intValue();
            List<ZooKeeperDto> list = zooKeeperDtoMapper.selectAll(description, status, pageOffset, pageSize);
            List<ZooKeeper> zooKeeperList = list.stream().map(zooKeeperDto -> {
                return zooKeeperDto.copy();
            }).collect(Collectors.toList());
            pageInfo.setRecords(zooKeeperList);
            return pageInfo;
        }

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result addZooKeeper(String zooKeeperKey, String description, String addressList, String digest, String status) throws RuntimeException {
        ZooKeeperDto zooKeeperDto = zooKeeperDtoMapper.selectByZooKeeperKey(zooKeeperKey);
        if (zooKeeperDto != null) {
            return Result.fail("ZooKeeper[%s]已经存在", zooKeeperKey);
        }
        CuratorFramework curatorFramework = spring.cloud.tasks.common.curator.CuratorFactory.connect(addressList, digest, null, CuratorFactory.shortTime_true);
        if (curatorFramework == null) {
            return Result.fail("连接ZooKeeper失败", zooKeeperKey);
        }
        //
        String userId = "CXL";
        Date now = new Date();
        zooKeeperDto = new ZooKeeperDto();
        zooKeeperDto.setCreatedBy(userId);
        zooKeeperDto.setCreateTime(now);
        zooKeeperDto.setLastUpdatedBy(userId);
        zooKeeperDto.setLastUpdateTime(now);
        //
        zooKeeperDto.setDescription(description);
        zooKeeperDto.setZooKeeperKey(zooKeeperKey);
        zooKeeperDto.setAddressList(addressList);
        zooKeeperDto.setDigest(digest);
        zooKeeperDto.setStatus(status);
        zooKeeperDtoMapper.insert(zooKeeperDto);
        return Result.success("添加连接信息成功");
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result updateZooKeeper(String zooKeeperKey, String description, String addressList, String digest, String status) throws RuntimeException {
        ZooKeeperDto zooKeeperDto = zooKeeperDtoMapper.selectByZooKeeperKey(zooKeeperKey);
        if (zooKeeperDto == null) {
            return Result.fail("ZooKeeper[%s]不存在", zooKeeperKey);
        }
        CuratorFramework curatorFramework = spring.cloud.tasks.common.curator.CuratorFactory.connect(addressList, digest, null, CuratorFactory.shortTime_true);
        if (curatorFramework == null) {
            return Result.fail("连接ZooKeeper失败", zooKeeperKey);
        }
        String userId = "CXL";
        Date now = new Date();
        zooKeeperDto.setLastUpdatedBy(userId);
        zooKeeperDto.setLastUpdateTime(now);
        //
        zooKeeperDto.setDescription(description);
        zooKeeperDto.setAddressList(addressList);
        zooKeeperDto.setDigest(digest);
        zooKeeperDto.setStatus(status);
        zooKeeperDtoMapper.updateByZooKeeperKey(zooKeeperDto);
        return Result.success("修改连接信息成功");
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result updateZooKeeperStatus(String zooKeeperKey, String status) {
        ZooKeeperDto zooKeeperDto = zooKeeperDtoMapper.selectByZooKeeperKey(zooKeeperKey);
        if (zooKeeperDto == null) {
            throw new RuntimeException(String.format("ZooKeeper[%s]不存在", zooKeeperKey));
        }
        zooKeeperDto.setStatus(status);
        zooKeeperDtoMapper.updateByZooKeeperKey(zooKeeperDto);
        return Result.success("修改连接信息状态成功");
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result deleteZooKeeper(String zooKeeperKey) throws RuntimeException {
        ZooKeeper zooKeeper = getZooKeeper(zooKeeperKey);
        if (zooKeeper == null) {
            return Result.fail("连接信息不存在");
        }
        List<String> nameSpaceList = nameSpaceDtoMapper.getNamespaceKeyListByZookeeperKey(zooKeeperKey);
        if (!CollectionUtils.isEmpty(nameSpaceList)) {
            return Result.fail("ZooKeeper下NameSpace不为空");
        }
        zooKeeperDtoMapper.deleteByZooKeeperKey(zooKeeperKey);
        return Result.success("删除连接信息成功");
    }

    //##<!-我是优美的功能模块分割线->##
    @Override
    public List<HashMap<String, String>> getZooKeeperKeyAndDescriptionList() {
        return zooKeeperDtoMapper.getZooKeeperKeyAndDescriptionList();//只显示有效的
    }

    @Override
    public PageInfo getNamespaceList(String zookeeperKey, String description, String status, Integer page, Integer limit) {
        int count = nameSpaceDtoMapper.selectAllCount(zookeeperKey, description, status);
        if (count == 0) {
            PageInfo pageInfo = new PageInfo(new ArrayList<ZooKeeper>());
            return pageInfo;
        } else {
            PageInfo pageInfo = new PageInfo(page, limit, count);
            Integer pageOffset = pageInfo.getCurrentPageOffset();
            Integer pageSize = limit.intValue();
            List<NamespaceDto> namespaceDtoList = nameSpaceDtoMapper.selectAll(zookeeperKey, description, status, pageOffset, pageSize);
            List<NamespaceVo> namespaceVoList = new ArrayList<>();
            for (NamespaceDto namespaceDto : namespaceDtoList) {
                NamespaceVo namespaceVo = new NamespaceVo();
                namespaceVo.copy(namespaceDto);
                namespaceVoList.add(namespaceVo);
            }
            List<String> zooKeeperKeyList = new ArrayList<>();
            for (NamespaceVo namespaceVo : namespaceVoList) {
                if (!zooKeeperKeyList.contains(namespaceVo.getZookeeperKey())) {
                    zooKeeperKeyList.add(namespaceVo.getZookeeperKey());
                }
            }
            Map<String, String> zooKeeperKeyToDescriptionMap = new HashMap<>();
            HashMap<String, Object> params = new HashMap<>();
            params.put("zooKeeperKeyList", zooKeeperKeyList);
            List<ZooKeeperDto> zooKeeperDtoList = zooKeeperDtoMapper.getZooKeeperDtoList(params);
            for (ZooKeeperDto zooKeeperDto : zooKeeperDtoList) {
                zooKeeperKeyToDescriptionMap.put(zooKeeperDto.getZooKeeperKey(), zooKeeperDto.getDescription());
            }
            for (NamespaceVo namespaceVo : namespaceVoList) {
                namespaceVo.setZookeeperDescription(zooKeeperKeyToDescriptionMap.get(namespaceVo.getZookeeperKey()));
            }
            pageInfo.setRecords(namespaceVoList);
            return pageInfo;
        }
    }

    //##<!-我是优美的功能模块分割线->##
    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Result addNamespace(NamespaceDto namespaceDto, String userId) throws RuntimeException {
        try {
            if (namespaceDto.getTaskMaxNum() > 1024) {//任务数最大只支持1024 如果更大自己修改代码
                return Result.warn("任务数最大只支持1024");
            }
            String zooKeeperKey = namespaceDto.getZookeeperKey();
            String namespaceKey = namespaceDto.getNamespaceKey();
            namespaceDto.setNamespaceKey(namespaceKey = namespaceKey.trim());//前端保证不为空
            ZooKeeper zooKeeper = getZooKeeper(zooKeeperKey);
            if (zooKeeper == null) {
                return Result.fail("连接信息:" + zooKeeperKey + "不存在");
            }
            if (nameSpaceDtoMapper.selectByNamespaceKey(namespaceKey) != null) {
                return Result.fail("命名空间:" + namespaceKey + "已经存在");
            }
            nameSpaceDtoMapper.insert(namespaceDto);
            return Result.success("添加命名空间成功");
        } catch (Exception e) {
            log.error(ExceptionUtils.getStackTrace(e));
            return Result.success("添加命名空间失败");
        }
    }

    @Override
    public Result updateNamespace(NamespaceDto namespaceDto, String userId) {
        if (namespaceDto.getTaskMaxNum() > 1024) {//任务数最大只支持1024 如果更大自己修改代码
            return Result.warn("任务数最大只支持1024");
        }
        String namespaceKey = namespaceDto.getNamespaceKey();
        if (namespaceKey == null) {
            return Result.fail("命名空间namespaceKey为空");
        }
        NamespaceDto dto = nameSpaceDtoMapper.selectByNamespaceKey(namespaceKey);
        if (dto == null) {
            return Result.fail("命名空间:" + namespaceKey + "不存在");
        }
        //zooKeeperKey不能进行改变
        String zooKeeperKey = namespaceDto.getZookeeperKey();
        String zooKeeperKeyInDto = dto.getZookeeperKey();
        if (!zooKeeperKeyInDto.equals(zooKeeperKey)) {
            return Result.fail("连接信息不一致");
        }
        ZooKeeper zooKeeper = getZooKeeper(zooKeeperKey);
        if (zooKeeper == null) {
            return Result.fail("连接信息:" + zooKeeperKey + "不存在");
        }
        nameSpaceDtoMapper.updateByNamespaceKey(namespaceDto);
        return Result.success("修改命名空间信息成功");
    }

    @Override
    public Result updateNamespaceStatus(String namespaceKey, String status) {
        try {
            NamespaceDto namespaceDto = nameSpaceDtoMapper.selectByNamespaceKey(namespaceKey);
            if (namespaceDto == null) {
                return Result.fail("命名空间:" + namespaceKey + "不存在");
            }
            String userId = "CXL";
            namespaceDto = new NamespaceDto();
            namespaceDto.setLastUpdatedBy(userId);
            namespaceDto.setLastUpdateTime(new Date());
            namespaceDto.setNamespaceKey(namespaceKey);
            namespaceDto.setStatus(status);
            nameSpaceDtoMapper.updateNamespaceStatus(namespaceDto);
            return Result.success("修改命名空间状态成功");
        } catch (Exception e) {
            log.error(ExceptionUtils.getStackTrace(e));
            return Result.success("修改命名空间失败");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result deleteNamespace(String namespaceKey) throws RuntimeException {
        boolean existOnlineExecutors = false;
        try {
            //existOnlineExecutors = existOnlineExecutors(namespaceKey);
        } catch (Exception e) {
            return Result.fail("连接命名空间:" + namespaceKey + "对应的ZooKeeper失败,删除命名空间失败");
        }
        if (existOnlineExecutors) {
            return Result.fail("命名空间:" + namespaceKey + "存在执行器正在执行,请先设置任务disable停止任务");
        } else {
            try {
                NamespaceDto nameSpaceDto = nameSpaceDtoMapper.selectByNamespaceKey(namespaceKey);
                if (nameSpaceDto == null) {
                    return Result.fail("命名空间:" + namespaceKey + "不存在");
                }
                String zooKeeperKey = nameSpaceDto.getZookeeperKey();
                ZooKeeperDto zooKeeperDto = zooKeeperDtoMapper.selectByZooKeeperKey(zooKeeperKey);
                if (nameSpaceDto == null) {
                    return Result.fail("连接信息:" + zooKeeperKey + "不存在");
                }
                CuratorInfo curatorInfo = new CuratorInfo();
                curatorInfo.setZookeeperKey(nameSpaceDto.getZookeeperKey());
                curatorInfo.setAddressList(zooKeeperDto.getAddressList());
                curatorInfo.setDigest(zooKeeperDto.getDigest());
                curatorInfo.setNamespaceKey(namespaceKey);
                deleteNameSpaceInZooKeeper(curatorInfo);
                deleteByNamespaceKey(namespaceKey);
                return Result.success("删除命名空间成功");
            } catch (Exception e) {
                log.error(ExceptionUtils.getStackTrace(e));
                return Result.success("删除命名空间失败");
            }
        }
    }

    protected void deleteByNamespaceKey(String nameSpace) {
        taskConfigurationDtoMapper.deleteByNamespaceKey(nameSpace);
        nameSpaceDtoMapper.deleteByNamespaceKey(nameSpace);
    }

    @Override
    public Result getNamespaceKeyAndDescriptionList() {
        Result result = Result.success();
        List<NamespaceDto> namespaceDtoList = nameSpaceDtoMapper.getNamespaceKeyAndDescriptionListForTaskManagerPage();
        result.setData(namespaceDtoList);
        return result;
    }
    //##<!-我是优美的功能模块分割线->##

    //##<!-我是优美的功能模块分割线->##
    @Override
    public CuratorInfo getCuratorInfo(String namespaceKey) {
        NamespaceDto namespaceDto = nameSpaceDtoMapper.selectByNamespaceKey(namespaceKey);
        if (namespaceDto == null) {
            throw new RuntimeException("命名空间:" + namespaceKey + "不存在");
        }
        String zooKeeperKey = namespaceDto.getZookeeperKey();
        ZooKeeperDto zooKeeperDto = zooKeeperDtoMapper.selectByZooKeeperKey(zooKeeperKey);
        if (zooKeeperDto == null) {
            throw new RuntimeException("连接信息:" + zooKeeperKey + "不存在");
        }
        CuratorInfo curatorInfo = new CuratorInfo();
        curatorInfo.setZookeeperKey(zooKeeperKey);
        curatorInfo.setAddressList(zooKeeperDto.getAddressList());
        curatorInfo.setDigest(zooKeeperDto.getDigest());
        curatorInfo.setNamespaceKey(namespaceKey);
        return curatorInfo;
    }

    @Override
    public List<CuratorInfo> getCuratorInfoList(String zookeeperKey) {
        ZooKeeperDto zooKeeperDto = zooKeeperDtoMapper.selectByZooKeeperKey(zookeeperKey);//获取最新的ZK信息
        if (zooKeeperDto == null) {
            return new ArrayList<>();
        }
        List<String> namespaceKeyList = nameSpaceDtoMapper.getNamespaceKeyListByZookeeperKey(zookeeperKey);
        if (namespaceKeyList == null) {
            return new ArrayList<>();
        }
        List<CuratorInfo> list = new ArrayList<>();
        for (String namespaceKey : namespaceKeyList) {
            CuratorInfo curatorInfo = new CuratorInfo();
            curatorInfo.setZookeeperKey(zooKeeperDto.getZooKeeperKey());
            curatorInfo.setAddressList(zooKeeperDto.getAddressList());
            curatorInfo.setDigest(zooKeeperDto.getDigest());
            curatorInfo.setNamespaceKey(namespaceKey);
            list.add(curatorInfo);
        }
        return list;
    }

    //
    @Override
    public List<ZooKeeper> getOnlineZooKeeperList() {
        List<ZooKeeper> zooKeeperList = zooKeeperDtoMapper.selectAll(null, null, null, null).stream().map(zooKeeperDto -> {
            return zooKeeperDto.copy();
        }).collect(Collectors.toList());
        for (ZooKeeper zooKeeper : zooKeeperList) {
            if (zooKeeper.isOnline()) {
                zooKeeperList.add(zooKeeper);
            }
        }
        return zooKeeperList;
    }

    /**
     * 构建新的ZooKeeper 该类不进行页面交互，内存驻留
     */
    @Override
    public ZooKeeper getZooKeeper(String zooKeeperKey) {
        ZooKeeperDto zooKeeperDto = zooKeeperDtoMapper.selectByZooKeeperKey(zooKeeperKey);
        if (zooKeeperDto == null) {
            return null;
        }
        return zooKeeperDto.copy();
    }

    @Setter
    @Getter
    public static class NamespaceVo extends NamespaceDto {
        private String zookeeperDescription;//该字段只是用于显示
        private boolean online;
        private boolean statusFlag;

        public void updateStatusFlag() {
            setStatusFlag("Y".equals(getStatus()));
        }

        public void copy(NamespaceDto namespaceDto) {
            this.setId(namespaceDto.getId());
            this.setCreatedBy(namespaceDto.getCreatedBy());
            this.setCreateTime(namespaceDto.getCreateTime());
            this.setLastUpdatedBy(namespaceDto.getLastUpdatedBy());
            this.setLastUpdateTime(namespaceDto.getLastUpdateTime());
            //
            this.setDescription(namespaceDto.getDescription());
            this.setZookeeperKey(namespaceDto.getZookeeperKey());
            this.setNamespaceKey(namespaceDto.getNamespaceKey());
            this.setStatus(namespaceDto.getStatus());
            updateStatusFlag();
            this.setHotPeriodStartDate(namespaceDto.getHotPeriodStartDate());
            this.setHotPeriodEndDate(namespaceDto.getHotPeriodEndDate());
            this.setTaskMaxNum(namespaceDto.getTaskMaxNum());
            online = true;
        }
    }


}
